﻿namespace Microsoft.SharePoint.Client
{
    using System;
    using System.Collections.Generic;
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Windows;
    using System.Windows.Resources;

    internal static class ScriptTypeMap
    {
        private static Dictionary<string, ScriptTypeInfo> s_clientProxies = new Dictionary<string, ScriptTypeInfo>();
        private static volatile bool s_inited;
        private static Dictionary<string, object> s_loadedAssemblies = new Dictionary<string, object>();
        private static object s_lock = new object();
        private static List<IScriptTypeFactory> s_scriptTypeFactories = new List<IScriptTypeFactory>();

        internal static void AddClientProxyAssembly(Assembly assembly)
        {
            lock (s_lock)
            {
                if (!s_loadedAssemblies.ContainsKey(assembly.FullName))
                {
                    foreach (Type type in assembly.GetTypes())
                    {
                        if (type.IsClass)
                        {
                            object[] objArray = type.GetCustomAttributes(typeof(ScriptTypeAttribute), false);
                            if (objArray.Length > 0)
                            {
                                ScriptTypeAttribute attribute = (ScriptTypeAttribute) objArray[0];
                                if (!string.IsNullOrEmpty(attribute.ScriptType) && typeof(IFromJson).IsAssignableFrom(type))
                                {
                                    s_clientProxies[attribute.ScriptType] = new ScriptTypeInfo(type, attribute.ValueObject);
                                    if (!string.IsNullOrEmpty(attribute.TypeAlias))
                                    {
                                        s_clientProxies[attribute.TypeAlias] = s_clientProxies[attribute.ScriptType];
                                    }
                                }
                            }
                        }
                    }
                    object[] customAttributes = assembly.GetCustomAttributes(typeof(ClientTypeAssemblyAttribute), false);
                    if ((customAttributes != null) || (customAttributes.Length != 0))
                    {
                        ClientTypeAssemblyAttribute attribute2 = (ClientTypeAssemblyAttribute) customAttributes[0];
                        if (attribute2.ScriptTypeFactory != null)
                        {
                            IScriptTypeFactory item = Activator.CreateInstance(attribute2.ScriptTypeFactory) as IScriptTypeFactory;
                            if (item != null)
                            {
                                s_scriptTypeFactories.Add(item);
                            }
                        }
                    }
                    s_loadedAssemblies[assembly.FullName] = null;
                }
            }
        }

        public static IFromJson CreateObjectFromScriptType(string scriptType, ClientRuntimeContext context)
        {
            EnsureInited();
            foreach (IScriptTypeFactory factory in s_scriptTypeFactories)
            {
                IFromJson json = factory.CreateObjectFromScriptType(scriptType, context);
                if (json != null)
                {
                    return json;
                }
            }
            ScriptTypeInfo info = null;
            if (!s_clientProxies.TryGetValue(scriptType, out info))
            {
                return null;
            }
            if (info.ValueObject)
            {
                return (Activator.CreateInstance(info.Type) as IFromJson);
            }
            object[] args = new object[2];
            args[0] = context;
            return (Activator.CreateInstance(info.Type, args) as IFromJson);
        }

        internal static void EnsureInited()
        {
            if (!s_inited)
            {
                lock (s_lock)
                {
                    if (!s_inited)
                    {
                        Init();
                        s_inited = true;
                    }
                }
            }
        }

        public static Type GetTypeFromScriptType(string scriptType)
        {
            EnsureInited();
            ScriptTypeInfo info = null;
            if (s_clientProxies.TryGetValue(scriptType, out info))
            {
                return info.Type;
            }
            return null;
        }

        private static void Init()
        {
            List<Assembly> list = new List<Assembly>();
            foreach (AssemblyPart part in Deployment.Current.Parts)
            {
                try
                {
                    StreamResourceInfo resourceStream = Application.GetResourceStream(new Uri(part.Source, UriKind.Relative));
                    if (resourceStream != null)
                    {
                        Assembly item = part.Load(resourceStream.Stream);
                        list.Add(item);
                    }
                    continue;
                }
                catch (Exception)
                {
                    continue;
                }
            }
            foreach (Assembly assembly2 in list)
            {
                try
                {
                    object[] customAttributes = assembly2.GetCustomAttributes(typeof(ClientTypeAssemblyAttribute), false);
                    if ((customAttributes != null) && (customAttributes.Length != 0))
                    {
                        AddClientProxyAssembly(assembly2);
                    }
                    continue;
                }
                catch (Exception)
                {
                    continue;
                }
            }
        }

        internal static bool IsInited
        {
            get
            {
                return s_inited;
            }
        }

        private class ScriptTypeInfo
        {
            public System.Type Type;
            public bool ValueObject;

            public ScriptTypeInfo(System.Type type, bool valueObject)
            {
                this.Type = type;
                this.ValueObject = valueObject;
            }
        }
    }
}

